#include "DXUT.h"
#include "BoundingVolume.h"
 
inline D3DXVECTOR3 MinVertor(const D3DXVECTOR3 & v1,const D3DXVECTOR3 & v2)
{
	D3DXVECTOR3 result;
	result .x= v1.x<v2.x?v1.x:v2.x;
	result .y= v1.y<v2.y?v1.y:v2.y;
	result .z= v1.z<v2.z?v1.z:v2.z;

	return result;
}
inline D3DXVECTOR3 MaxVertor(const D3DXVECTOR3 & v1,const D3DXVECTOR3 & v2)
{
	D3DXVECTOR3 result;
	result .x= v1.x<v2.x?v2.x:v1.x;
	result .y= v1.y<v2.y?v2.y:v1.y;
	result .z= v1.z<v2.z?v2.z:v1.z;

	return result;
}
void ComputeBoundingAxisAlignedBoxFromPoints( AxisAlignedBox* pOut, UINT Count, const D3DXVECTOR3* pPoints )
{
	assert(pOut);
	assert( Count > 0 );
	assert( pPoints );

	// Find the minimum and maximum x, y, and z
	D3DXVECTOR3 vMin, vMax;

	vMin = vMax =  ( *pPoints );

	for( UINT i = 1; i < Count; i++ )
	{
		D3DXVECTOR3 Point =  pPoints[i];

		vMin = MinVertor( vMin, Point );
		vMax = MaxVertor( vMax, Point );
	}

	// Store center and extents.
	pOut->Center=( vMin + vMax ) * 0.5f ;
	pOut->Extents=( vMax - vMin ) * 0.5f ;

	return;
}

void ComputeFrustumFromProjection( Frustum* pOut, const D3DXMATRIX *  pView , const D3DXMATRIX * pProjection )
{
	assert( pOut );
	assert( pProjection );

	// Corners of the projection frustum in homogenous space.
	static D3DXVECTOR3 HomogenousPoints[8] =
	{
		//front plane
		D3DXVECTOR3( -1.0f,  1.0f, 1.0f) ,  
		D3DXVECTOR3( -1.0f,  -1.0f, 1.0f) , //left
		D3DXVECTOR3( 1.0f,  -1.0f, 1.0f) , //Right
	    D3DXVECTOR3( 1.0f,  1.0f, 1.0f) , 



	 
		//back plane
		//front plane
		D3DXVECTOR3( -1.0f,  1.0f, 0.0f) ,  
		D3DXVECTOR3( -1.0f,  -1.0f, 0.0f) , //left
		D3DXVECTOR3( 1.0f,  -1.0f, 0.0f) , //Right
		D3DXVECTOR3( 1.0f,  1.0f, 0.0f) , 
	};

	float Determinant;
	D3DXMATRIX matInverse;

	D3DXMATRIX matViewProj=*pView**pProjection;
	D3DXMatrixInverse(&matInverse,&Determinant, &matViewProj);
	D3DXMATRIX matViewInverse;
	D3DXMatrixInverse(&matViewInverse,0,pView );
	 pOut->Origin= D3DXVECTOR3(matViewInverse._41,matViewInverse._42,matViewInverse._43);

	// Compute the frustum corners in world space.
	 
	 
	for( INT i = 0; i < 8; i++ )
	{
		 
		// Transform point.
		D3DXVec3TransformCoord(&pOut->Points[i],&HomogenousPoints[i],&matInverse);
	//	D3DXVec3TransformCoord(&pOut->points[i],&Points[i],&matViewInverse);
 
	}
 //  pOut->Origin = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );

  // D3DXMATRIX mat;
 //  D3DXMatrixIdentity(&mat);
 //   D3DXQuaternionRotationMatrix(&  pOut->Orientation,&mat);
 	// Compute the slopes.
	//    Points[0] = Points[0]/Points[0].z;
	//	Points[1] = Points[1]/Points[1].z;
	//	Points[2] = Points[2]/Points[2].z;
	//	Points[3] = Points[3]/Points[3].z;

	//	pOut->RightSlope =  Points[0].x;
	//pOut->LeftSlope =  Points[1].x;
	//pOut->TopSlope =  Points[2].y;
	//pOut->BottomSlope = Points[3].y ;

	// Compute near and far.
	/*
	pOut->Near = Points[4].z;
	pOut->Far =  Points[5].z ;*/
}

 

void DrawCube( C3DLineManager * pLineManager, const D3DXMATRIX& matWorld, D3DCOLOR Color )
{
	static D3DXVECTOR3 verts[8] =
	{
		D3DXVECTOR3( -1, -1, -1),
		D3DXVECTOR3( 1, -1, -1),
		D3DXVECTOR3( 1, -1, 1),
		D3DXVECTOR3( -1, -1, 1) ,
		D3DXVECTOR3( -1, 1, -1 ),
		D3DXVECTOR3( 1, 1, -1 ),
		D3DXVECTOR3( 1, 1, 1) ,
		D3DXVECTOR3( -1, 1, 1) 
	};
	static const WORD indices[] =
	{
		0, 1,
		1, 2,
		2, 3,
		3, 0,
		4, 5,
		5, 6,
		6, 7,
		7, 4,
		0, 4,
		1, 5,
		2, 6,
		3, 7
	};
	D3DXVECTOR3 ptBegin ,ptEnd;
 /* pLineManager->AddLine(  verts[1] , verts[0],Color,Color);
    pLineManager->AddLine(  verts[1] , verts[2],Color,Color);

	  pLineManager->AddLine(  verts[2] , verts[3],Color,Color);*/
  // pLineManager->AddLine(  verts[indices[i++]]*10, verts[indices[i++]]*10,Color,Color);


  //  pLineManager->AddLine(  verts[indices[i++]]*10, verts[indices[i++]]*10,Color,Color);

	for(int i=0; i<24; )
	{
		ptBegin= verts[indices[i++]];
		ptEnd =verts[indices[i++]];
		pLineManager->AddLine( ptBegin, ptEnd,Color,Color);
	}
 

 
}

void DrawFrustum(C3DLineManager * pLineManager,const Frustum& frustum, D3DCOLOR Color )
{
 
	 pLineManager->AddLine(  frustum.Points[0], frustum.Points[1]  ,Color,Color);
	 pLineManager->AddLine(  frustum.Points[1], frustum.Points[2]  ,Color,Color);
	 pLineManager->AddLine(  frustum.Points[2], frustum.Points[3]  ,Color,Color);
	 pLineManager->AddLine(  frustum.Points[3], frustum.Points[0]  ,Color,Color);


	 pLineManager->AddLine(  frustum.Points[4], frustum.Points[5]  ,Color,Color);
	 pLineManager->AddLine(  frustum.Points[5], frustum.Points[6]  ,Color,Color);
	 pLineManager->AddLine(  frustum.Points[6], frustum.Points[7]  ,Color,Color);
	 pLineManager->AddLine(  frustum.Points[7], frustum.Points[4]  ,Color,Color);



	 pLineManager->AddLine(  frustum.Origin, frustum.Points[0]  , Color*Color,Color);
	 pLineManager->AddLine(  frustum.Origin, frustum.Points[1]  , Color*Color,Color);
	 pLineManager->AddLine(  frustum.Origin, frustum.Points[2]  , Color*Color,Color);
	 pLineManager->AddLine( frustum.Origin, frustum.Points[3]  , Color*Color,Color);

  
}

void DrawBox( C3DLineManager * pLineManager, const D3DXMATRIX& matWorld, const BoundingBox & box ,D3DCOLOR Color )
{
	DXUTGetD3D9Device()->SetTransform(D3DTS_WORLD, &matWorld);

	D3DXVECTOR3 verts[8] =
	{
		D3DXVECTOR3( box.min.x,  box.min.y,  box.min.z),
		D3DXVECTOR3( box.max.x,  box.min.y,  box.min.z),
		D3DXVECTOR3( box.max.x,  box.min.y,  box.max.z),
		D3DXVECTOR3( box.min.x,  box.min.y,  box.max.z),
		D3DXVECTOR3( box.min.x,  box.max.y,  box.min.z),
		D3DXVECTOR3( box.max.x,  box.max.y,  box.min.z),
		D3DXVECTOR3( box.max.x,  box.max.y,  box.max.z),
		D3DXVECTOR3( box.min.x,  box.max.y,  box.max.z),
	};

	static const WORD indices[] =
	{
		0, 1,
		1, 2,
		2, 3,
		3, 0,
		4, 5,
		5, 6,
		6, 7,
		7, 4,
		0, 4,
		1, 5,
		2, 6,
		3, 7
	};
   D3DXVECTOR3 ptBegin ,ptEnd;
	for(int i=0; i<24; )
	{
		ptBegin= verts[indices[i++]];
		ptEnd =verts[indices[i++]];
		pLineManager->AddLine( ptBegin, ptEnd,Color,Color);
	}
}

void DrawSphere( BoundingSphere & sphere, D3DCOLOR Color )
{
 
	LPD3DXMESH pMesh;
	D3DXCreateSphere(DXUTGetD3D9Device(),sphere.radius,40,40,&pMesh,0);
	D3DXMATRIX matWorld;
	D3DXMATRIX matOldWorld;
	D3DXMatrixTranslation(&matWorld,sphere.centre.x, sphere.centre.y,sphere.centre.z);
	DXUTGetD3D9Device()->GetTransform(D3DTS_WORLD,&matOldWorld);
	DXUTGetD3D9Device()->SetTransform(D3DTS_WORLD,&matWorld);
	pMesh->DrawSubset(0);
	SAFE_RELEASE(pMesh);
	DXUTGetD3D9Device()->SetTransform(D3DTS_WORLD,&matOldWorld);
}

void DrawRing( IDirect3DDevice9* pd3dDevice, const D3DXVECTOR3 & vOrigin, const D3DXVECTOR3 & vMajor,const D3DXVECTOR3& vMinor, D3DCOLOR Color )
{
	//static const DWORD dwRingSegments = 32;

	//D3DXVECTOR3 verts[ dwRingSegments + 1 ];


 //
	//FLOAT fAngleDelta = D3DX_PI/ ( float )dwRingSegments;
	//// Instead of calling cos/sin for each segment we calculate
	//// the sign of the angle delta and then incrementally calculate sin
	//// and cosine from then on.
	//D3DXVECTOR3 cosDelta = D3DXVECTOR3( cosf( fAngleDelta ) ,cosf( fAngleDelta ),cosf( fAngleDelta ));
	//D3DXVECTOR3 sinDelta = D3DXVECTOR3( sinf( fAngleDelta ),sinf( fAngleDelta ),sinf( fAngleDelta ) );
	//D3DXVECTOR3 incrementalSin = D3DXVECTOR3(0,0,0);
	//static const  D3DXVECTOR3 initialCos =D3DXVECTOR3(1.0f,1.0f,1.0f);
 //
	//D3DXVECTOR3 incrementalCos = initialCos;
	//for( DWORD i = 0; i < dwRingSegments; i++ )
	//{
	//	D3DXVECTOR3 Pos;
	//	Pos.x = vOrigin.x+ vMajor.x * incrementalCos.x ;
	//	Pos.y = vOrigin.x+ vMajor.y * incrementalCos.y ;
	//	Pos.z = vOrigin.x+ vMajor.z * incrementalCos.z ;



	//	Pos.x = Pos.x+ vMinor.x * incrementalSin.x ;
	//	Pos.y = Pos.x+ vMinor.y * incrementalSin.y ;
	//	Pos.z = Pos.x+ vMinor.z * incrementalSin.z ;


	// 
	//	 verts[i]=Pos ;
	//	// Standard formula to rotate a vector.
	//	D3DXVECTOR3 newCos;
	//	newCos.x= incrementalCos.x * cosDelta.x - incrementalSin.x * sinDelta.x;
 //       newCos.y= incrementalCos.y * cosDelta.y - incrementalSin.y * sinDelta.y;
	//	newCos.z= incrementalCos.z * cosDelta.z - incrementalSin.z * sinDelta.z;
 
	//	D3DXVECTOR3 newSin ;
	//	newSin.x= incrementalCos.x * sinDelta.x + incrementalSin.x * cosDelta.x;
	//	newSin.y= incrementalCos.y * sinDelta.y + incrementalSin.y * cosDelta.y;
	//	newSin.z= incrementalCos.z * sinDelta.z + incrementalSin.z * cosDelta.z;

 //
	//	incrementalCos = newCos;
	//	incrementalSin = newSin;
	//}
	//verts[ dwRingSegments ] = verts[0];

 //

	//D3DXVECTOR3* pVerts = NULL;
	//HRESULT hr;
	////V( g_pVB->Lock( 0, 0, (void**)&pVerts, D3DLOCK_DISCARD ) )
	////	memcpy( pVerts, verts, sizeof(verts) );
	////V( g_pVB->Unlock() )

	//	// Draw ring
	//	D3DXCOLOR clr = Color;
 //
	//pd3dDevice->DrawPrimitive( D3DPT_LINESTRIP, 0, dwRingSegments );
}

void DrawBoundingBox( C3DLineManager * pLineManager, const D3DXMATRIX * pmatWorld, class BoundingBox * box ,D3DCOLOR Color )
{
	if(!box)
		return ;

	if(pmatWorld)
	DXUTGetD3D9Device()->SetTransform(D3DTS_WORLD, pmatWorld);

	D3DXVECTOR3 verts[8] =
	{
		D3DXVECTOR3( box->min.x,  box->min.y,  box->min.z),
		D3DXVECTOR3( box->max.x,  box->min.y,  box->min.z),
		D3DXVECTOR3( box->max.x,  box->min.y,  box->max.z),
		D3DXVECTOR3( box->min.x,  box->min.y,  box->max.z),
		D3DXVECTOR3( box->min.x,  box->max.y,  box->min.z),
		D3DXVECTOR3( box->max.x,  box->max.y,  box->min.z),
		D3DXVECTOR3( box->max.x,  box->max.y,  box->max.z),
		D3DXVECTOR3( box->min.x,  box->max.y,  box->max.z),
	};

	static const WORD indices[] =
	{
		0, 1,
		1, 2,
		2, 3,
		3, 0,
		4, 5,
		5, 6,
		6, 7,
		7, 4,
		0, 4,
		1, 5,
		2, 6,
		3, 7
	};
	D3DXVECTOR3 ptBegin ,ptEnd;
	for(int i=0; i<24; )
	{
		ptBegin= verts[indices[i++]];
		ptEnd =verts[indices[i++]];
		pLineManager->AddLine( ptBegin, ptEnd,Color,Color);
	}
	 
}








 